/*
 * @(#)BeansSorter.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.framework.bean;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.beanutils.PropertyUtils;

/**
 * @author          Ryan Kwan
 * @company         DCIVision Limited
 * @creation date   $Date: 2007/07/23 07:43:35 $
 * @version $Revision: 1.3.2.1 $ 
 */
public class BeansSorter {
    
    public static final String REVISION = "$Revision: 1.3.2.1 $";

    public static final int SORT_ASCENDING = 0;
    public static final int SORT_DESCENDING = 1;
    
    protected static List sort(Collection source, String attribute) {
        if(source == null) {
          return null;
        }
        List list = makeUnsortedBeanList(source,attribute);
        Collections.sort(list);
        ArrayList sortedList = new ArrayList(source.size());
        for(Iterator i = list.iterator(); i.hasNext();){
            sortedList.add(((BeanSorterElement)i.next()).getBean());
        }
        return sortedList;
    }
   
   public static List sort(Collection source, String attribute, int direction) {
        return sort(new ArrayList(source), attribute, direction);        
    }
    
    public static List sortAscending(Collection source, String attribute){
        return sort(source,attribute, SORT_ASCENDING);
    }
    
    public static List sortDescending(Collection source, String attribute){
        return sort(source,attribute,SORT_DESCENDING);
    }
    
    public static List sort(List source, String attribute, int direction) {
        if(source == null) {
          return null;
        }
        List sortedList = sort(source,attribute);
        if(direction == SORT_ASCENDING){
            return sortedList;
        }else{
            Collections.reverse(sortedList);
            return sortedList;
        }
    }
    
    public static List sortAscending(List source, String attribute){
        return sort(source,attribute, SORT_ASCENDING);
    }
    
    public static List sortDescending(List source, String attribute){
        return sort(source,attribute,SORT_DESCENDING);
    }
    
   /**
    * Split the collection into sub-collections by a range value, then sort 
    * each sub-collections by the given attribute 
    *
    * @param source  the input to be sorted
    * @param range   the data range to be split
    * @param rangeAttribute  the attribute to be slict, e.g. ID
    * @param rangeDirection  the direction to sort the groups
    * @param attribute       the bean's attribute to be sort in each group
    * @param direction	     the direction to sort in each group
    * @return  the sorted value
    */
    public static List rangeSort(Collection source, int range, String rangeAttribute, 
                                 int rangeDirection, String attribute, int direction){
      List firstSortedList = sort(source,attribute,rangeDirection);
      List finalSortedList = new ArrayList();
      Map rangeMap = new TreeMap();
      for(int i=0;i<firstSortedList.size();i++){
        Object bean = firstSortedList.get(i);
        int id = Integer.parseInt(getKey(bean,rangeAttribute).toString());
        int rangeSegment = (int)(id / range);
        Integer key = new Integer(rangeSegment);
        if(rangeMap.get(key)==null){
          List subSortedList = new ArrayList();
          rangeMap.put(key,subSortedList);
          subSortedList.add(bean);
        }else{
          List subSortedList = (List)rangeMap.get(key);
          subSortedList.add(bean);
        }
	  }
	  Iterator subListIter = rangeMap.values().iterator();
	  while(subListIter.hasNext()){
	    finalSortedList.addAll((List)subListIter.next());
      }
	  return finalSortedList;
    }    
    
    protected static List makeUnsortedBeanList(Collection source,String attribute) {
        ArrayList unsortedList = new ArrayList(source.size() * 2);
        Object bean;
        for(Iterator i = source.iterator(); i.hasNext();){
            bean = i.next();
            Object key = getKey(bean, attribute);
            //log.debug("key:"+key);
            unsortedList.add(new BeanSorterElement(key, bean));
        }        
        return unsortedList;
    }
    
    protected static Object getKey(Object bean, String attribute) {
        if(attribute == null) {
          return bean;
        }
        try {
            return PropertyUtils.getProperty(bean, attribute);
        }
        catch(IllegalAccessException e) {
            throw new UnsupportedOperationException(e.getMessage());
        }
        catch(InvocationTargetException e) {
            throw new UnsupportedOperationException(e.getMessage());
        }
        catch(NoSuchMethodException e) {
            throw new UnsupportedOperationException(e.getMessage());
        }
    }
    
    
}
